package com.example.springboot.config.mvc;

import com.example.springboot.config.bootcustomize.locale.MyLocaleResolver;
import com.example.springboot.config.bootcustomize.messageconverter.CzkMessageConverter;
import com.example.springboot.config.bootcustomize.messageconverter.MyMessageConverter;
import com.example.springboot.config.bootcustomize.parameterFormat.MyParameterFormat;
import com.example.springboot.config.bootcustomize.parameteranotation.UserParamAnnotationImpl;
import com.example.springboot.config.interceptors.LogMdcInterceptor;
import com.example.springboot.config.interceptors.RedisUrlCountInterceptor;
import com.example.springboot.config.interceptors.RequestLimitInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.accept.ParameterContentNegotiationStrategy;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.util.UrlPathHelper;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @EnableWebMvc 全面接管springmvc，全部由我们自己配置
 * @Author:ChenZhangKun
 * @Date: 2020/9/14 19:00
 */
//@EnableWebMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {


    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 浏览器访问czk的url，也会被解析到success.html
        registry.addViewController("/czk").setViewName("success");
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new UserParamAnnotationImpl());
    }

    /**
     * 所有的WebMvcConfigurer都会起作用，自己注册一个
     */
    @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        WebMvcConfigurer webMvcConfigurer = new WebMvcConfigurer() {
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                // 实现方法
                // 实现restful风格，默认访问首页
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login");
                registry.addViewController("/main.html").setViewName("dashboard");
            }

            @Autowired
            private RedisUrlCountInterceptor redisUrlCountInterceptor;
            @Autowired
            private RequestLimitInterceptor requestLimitInterceptor;

            /**
             * 注册拦截器
             * @param registry
             */
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                // 拦截所有请求
            /*    registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
                        // 排除请求
                        .excludePathPatterns("/index.html","/","/user/login","/asserts","/favicon.ico");*/
                registry.addInterceptor(redisUrlCountInterceptor)
                        .excludePathPatterns(Arrays.asList("/index.html", "/", "/user/login", "/asserts", "/favicon.ico", "/resources/**"));
                registry.addInterceptor(requestLimitInterceptor)
                        .excludePathPatterns(Arrays.asList("/index.html", "/", "/user/login", "/asserts", "/favicon.ico", "/resources/**"));
                // slf4j mdc拦截器
                registry.addInterceptor(new LogMdcInterceptor())
                        .excludePathPatterns("/index.html", "/", "/user/login", "/asserts", "/favicon.ico", "/resources/** ");
            }

            /**
             * 添加资源映射器
             * @param registry
             */
            @Override
            public void addResourceHandlers(ResourceHandlerRegistry registry) {
                registry.addResourceHandler("/static/**")
                        .addResourceLocations("classpath:/static/");
            }

        };
        return webMvcConfigurer;
    }

    /**
     * 将自己的国际化加载容器中
     */
    @Bean
    public LocaleResolver localeResolver() {
        return new MyLocaleResolver();
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 添加到消息转换器集合
        converters.add(myMessageConverter());
        converters.add(new CzkMessageConverter());
    }

    @Bean
    public MyMessageConverter myMessageConverter() {
        return new MyMessageConverter();
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        // 开启矩阵变量
        // 设置不移除分号后面的内容
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }

    /**
     * 添加自己的类型格式化转换器
     *
     * @param registry
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new MyParameterFormat());
    }

    /**
     * 自定义内容协商策略
     * format=czk  format=nqz
     *
     * @param configurer
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        // 加入自己的内容协商策略
        Map<String, MediaType> mediaTypes = new HashMap<>(16);
        // json
        mediaTypes.put("json", MediaType.APPLICATION_JSON);
        // xml
        mediaTypes.put("xml", MediaType.APPLICATION_XML);
        // czk类型
        mediaTypes.put("czk", MediaType.parseMediaType("application/czk"));
        // nzq类型
        mediaTypes.put("nzq", MediaType.parseMediaType("application/nzq"));
        // 指定支持解析哪些参数对应的哪些媒体类型
        ParameterContentNegotiationStrategy parameterContentNegotiationStrategy = new ParameterContentNegotiationStrategy(mediaTypes);
        // 添加适配请求头的策略，不然添加自己策略后会失效
        HeaderContentNegotiationStrategy headerContentNegotiationStrategy = new HeaderContentNegotiationStrategy();
        // 加入
        configurer.strategies(Arrays.asList(parameterContentNegotiationStrategy, headerContentNegotiationStrategy));
    }

    /**
     * 添加静态资源映射
     * http://localhost:8083/czk/image/1.jpg 访问saved Pictures的文件
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/image/**").addResourceLocations("file:C:\\Users\\CZK\\Pictures\\Saved Pictures\\");
    }


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 允许所有接口
                .allowCredentials(true) // 是否发生cookie
                .allowedMethods("GET", "POST", "DELETE", "PUT") // 允许的方法
                .allowedHeaders("*");
    }
}
